<template>
  <div class="ws-demo">
    <h2>Vue WebSocket 测试 Demo</h2>
    
    <!-- 连接状态 -->
    <div class="status">
      连接状态：
      <span :class="connected ? 'connected' : 'disconnected'">
        {{ connected ? '已连接' : '未连接' }}
      </span>
    </div>

    <!-- 消息列表 -->
    <div class="message-list">
      <div v-for="(msg, index) in messages" :key="index" :class="['message', msg.type]">
        <span class="role">{{ msg.type === 'send' ? '我' : '服务器' }}：</span>
        <span class="content">{{ msg.content }}</span>
        <span class="time">{{ msg.time }}</span>
      </div>
    </div>

    <!-- 操作区域 -->
    <div class="operate-area">
      <input
        type="text"
        v-model="inputMessage"
        placeholder="输入消息..."
        :disabled="!connected"
      />
      <button @click="sendMessage" :disabled="!connected || !inputMessage">
        发送消息
      </button>
      <button @click="handleConnect" :disabled="connected">
        建立连接
      </button>
      <button @click="handleDisconnect" :disabled="!connected">
        断开连接
      </button>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'

// WebSocket 实例
let ws = null
// 连接状态
const connected = ref(false)
// 消息列表（存储发送/接收的消息）
const messages = ref([])
// 输入的消息内容
const inputMessage = ref('')

// 格式化时间（用于消息时间戳）
const formatTime = () => {
  const date = new Date()
  return `${date.getHours()}:${date.getMinutes().toString().padStart(2, '0')}:${date.getSeconds().toString().padStart(2, '0')}`
}

// 建立 WebSocket 连接
const handleConnect = () => {
  // 公共回声测试服务器（会将收到的消息原样返回）
  const wsUrl = 'ws://echo.websocket.events'
  
  // 创建 WebSocket 实例
  ws = new WebSocket(wsUrl)

  // 连接成功回调
  ws.onopen = () => {
    console.log('WebSocket 连接成功')
    connected.value = true
    messages.value.push({
      type: 'system',
      content: '连接已建立',
      time: formatTime()
    })
  }

  // 接收消息回调
  ws.onmessage = (event) => {
    console.log('收到服务器消息：', event.data)
    messages.value.push({
      type: 'receive', // 接收的消息
      content: event.data,
      time: formatTime()
    })
    // 自动滚动到最新消息
    scrollToBottom()
  }

  // 连接错误回调
  ws.onerror = (error) => {
    console.error('WebSocket 错误：', error)
    messages.value.push({
      type: 'system',
      content: `连接错误: ${error.message}`,
      time: formatTime()
    })
  }

  // 连接关闭回调
  ws.onclose = (event) => {
    console.log('WebSocket 连接关闭，代码：', event.code)
    connected.value = false
    messages.value.push({
      type: 'system',
      content: `连接已关闭 (代码: ${event.code})`,
      time: formatTime()
    })
    ws = null // 清空实例
  }
}

// 发送消息
const sendMessage = () => {
  if (!ws || !connected.value) return

  const msg = inputMessage.value.trim()
  if (!msg) return

  // 发送消息
  ws.send(msg)
  // 记录发送的消息
  messages.value.push({
    type: 'send', // 发送的消息
    content: msg,
    time: formatTime()
  })
  // 清空输入框
  inputMessage.value = ''
  // 自动滚动到最新消息
  scrollToBottom()
}

// 断开连接
const handleDisconnect = () => {
  if (ws && connected.value) {
    ws.close(1000, '主动断开连接') // 1000 是正常关闭代码
  }
}

// 自动滚动到消息列表底部
const scrollToBottom = () => {
  const messageList = document.querySelector('.message-list')
  if (messageList) {
    messageList.scrollTop = messageList.scrollHeight
  }
}

// 组件挂载时尝试连接
onMounted(() => {
  handleConnect()
})

// 组件卸载时关闭连接（防止内存泄漏）
onUnmounted(() => {
  handleDisconnect()
})
</script>

<style scoped>
.ws-demo {
  max-width: 800px;
  margin: 20px auto;
  padding: 20px;
  border: 1px solid #eee;
  border-radius: 8px;
}

.status {
  margin: 10px 0;
  padding: 10px;
  background: #f5f5f5;
  border-radius: 4px;
}

.connected {
  color: #4CAF50;
  font-weight: bold;
}

.disconnected {
  color: #f44336;
  font-weight: bold;
}

.message-list {
  height: 400px;
  overflow-y: auto;
  margin: 15px 0;
  padding: 10px;
  border: 1px solid #eee;
  border-radius: 4px;
}

.message {
  margin: 8px 0;
  padding: 8px 12px;
  border-radius: 4px;
  max-width: 70%;
}

.message.send {
  background: #e3f2fd;
  margin-left: auto;
}

.message.receive {
  background: #f1f8e9;
  margin-right: auto;
}

.message.system {
  background: #fff3e0;
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}

.role {
  font-weight: bold;
  margin-right: 8px;
}

.time {
  font-size: 12px;
  color: #888;
  margin-left: 10px;
}

.operate-area {
  display: flex;
  gap: 10px;
  align-items: center;
}

.operate-area input {
  flex: 1;
  padding: 8px 12px;
  border: 1px solid #ddd;
  border-radius: 4px;
}

.operate-area button {
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.operate-area button:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.operate-area button:not(:disabled):hover {
  opacity: 0.9;
}

.operate-area button:nth-of-type(1) {
  background: #2196F3;
  color: white;
}

.operate-area button:nth-of-type(2) {
  background: #4CAF50;
  color: white;
}

.operate-area button:nth-of-type(3) {
  background: #f44336;
  color: white;
}
</style>